#ifndef GS_LEXER_H
#define GS_LEXER_H

namespace Gs
{
	class String;
	class Context;
	class Lexer;

	// Represents a script token.
	class Token
	{
	public:
		// Specifies the type of token.
		enum TokenType
		{
			IdentifierToken,	// identifier
			KeywordToken,		// keyword
			OperatorToken,		// operator
			StringToken,		// "" or '' string
			IntegerToken,		// integer or hexadecimal
			FloatToken			// floating point
		};

		// Specifies the keyword or operator ids.
		enum ID
		{
			If,							// if
			Else,						// else
			For,						// for
			ForEach,					// foreach
			Do,							// do
			While,						// while
			To,							// to
			String,						// string
			Int,						// int
			In,							// in
			Float,						// float
			Function,					// function
			Class,						// class
			Var,						// var
			Object,						// object
			Global,						// global
			End,						// end
			True,						// true
			False,						// false

			LeftBracket,				// (
			RightBracket,				// )
			LeftBrace,					// {
			RightBrace,					// }
			Comma,						// ,
			Colon,						// :
			SemiColon,					// ;
			Equality,					// ==
			Assign,						// =
			Dot,						// .
			MultiplyAssign,				// *=
			Multiply,					// *
			Decrement,					// --
			MinusAssign,				// -=
			Minus,						// -
			Increment,					// ++
			PlusAssign,					// +=
			Plus,						// +
			DivideAssign,				// /=
			Divide,						// /
			ModulusAssign,				// %=
			Modulus,					// %
			OnesComplementAssign,		// ~=
			OnesComplement,				// ~
			Question,					// ?
			NotEqual,					// !=
			Not,						// !
			BitwiseLeftShiftAssign,		// <<=
			BitwiseLeftShift,			// <<
			LessThanOrEqual,			// <=
			LessThan,					// <
			BitwiseRightShiftAssign,	// >>=
			BitwiseRightShift,			// >>
			MoreThanOrEqual,			// >=
			MoreThan,					// >
			Or,							// ||
			BitwiseOrAssign,			// |=
			BitwiseOr,					// |
			And,						// &&
			BitwiseAndAssign,			// &=
			BitwiseAnd,					// &
			BitwiseXorAssign,			// ^=
			BitwiseXor,					// ^
		};

		// Stores the start index of the token in the script.
		int start;

		// Stores the length of the token.
		int length;

		// Stores the type of the token.
		short type;

		// Stores the identifier of the token.
		short identifier;

		// Stores a pointer to the next token.
		Token *next;

		// Converts the token to a string.
		Gs::String *ToString(Lexer *lexer);

		// Converts the token to a string.
		const char *ToString(Lexer *lexer, char *to);
	};
	
	// Represents a predefined token such as a keyword or operator.
	struct TokenDefinition
	{
		// Stores the token string literal.
		const char *token;
		
		// Stores the token ID.
		Token::ID id;
	};

	// Represents a script lexical analyser.
	class Lexer
	{
	private:
		// Stores the first token in the script.
		Token *_first;

		// Stores the last token since scanning.
		Token *_last;

		// Stores a pointer to the script string.
		const char *_script;

		// Stores the name of the script.
		const char *_source;

		// Stores a pointer to the Context.
		Context *_context;

	public:
		// Initialises a new instance of the Lexer class.
		Lexer(Context *context, const char *script, const char *source);

		// Destroys the instance.
		~Lexer();

		// Scans for the next token.
		bool Scan();

		// Scans the entire script.
		void ScanAll();

		// Gets a pointer to the script text.
		const char *GetScript();

		// Gets the first token in the script.
		Token *GetFirst();

		// Gets the last token since scanning.
		Token *GetLast();

		// Adds a token to the list.
		Token *AddToken(const char *start, int length, Token::TokenType type);

		// Gets the line and character index (one-based) for an index in the script.
		int GetLineAndColumn(int index, int &column);

		// Throws a formatted SyntaxErrorException.
		void Throw(int index, const char *format, ...);
	};
}

#endif